#include "vl_shared_memory.h"

#ifdef VL_POSIX
	#include <sys/ipc.h>
	#include <sys/types.h>
	#include <sys/shm.h>
#endif

using namespace VL;


/**
 * @Author: CimZzz
 * @Date: 2022-08-17 11:02:20
 * 
 * 构造方法
 * 
 * @param key 值指针
 * @param memoryCapacity 内存尺寸
 * @param numsOfSem 信号量数量
 */
SharedMemory::SharedMemory(std::shared_ptr<void> keyPtr, size_t memoryCapacity, bool notCreate): key(keyPtr), memoryCapacity(memoryCapacity), shmId(nullptr),
	isAttached(false), notCreate(notCreate) {

}

/**
 * @Author: CimZzz
 * @Date: 2022-08-17 11:02:37
 * 
 * 析构函数
 */
SharedMemory::~SharedMemory() {
	this->release();
}

/**
 * @Author: CimZzz
 * @Date: 2022-08-17 15:56:49
 * 
 * 初始化共享内存
 * 
 * @return 如果初始化成功返回 true
 */
bool SharedMemory::initSharedMemory() {
	if(this->isInited) {
		return true;
	}

	#ifdef VL_POSIX
		auto keyPtr = std::static_pointer_cast<key_t, void>(this->key);
		int shmId = !this->notCreate ? shmget(*keyPtr, this->memoryCapacity, 0666 | IPC_CREAT) : shmget(*keyPtr, this->memoryCapacity, 0666);
		if(shmId == -1) {
			// 创建 / 获取信号量失败
			return false;
		}
		
		this->shmId = std::shared_ptr<int>(new int(shmId));
	#endif //VL_POSIX

	this->isInited = true;

	return true;
}

/**
 * @Author: CimZzz
 * @Date: 2022-08-17 17:25:42
 * 
 * 标记为创建共享内存
 */
void SharedMemory::markNeedCreate() {
	if(this->isInited) {
		return;
	}

	this->notCreate = false;
}

/**
 * @Author: CimZzz
 * @Date: 2022-08-17 15:18:56
 * 
 * 标记为不创建共享内存
 */
void SharedMemory::markNotCreate() {
	if(this->isInited) {
		return;
	}

	this->notCreate = true;
}

/**
 * @Author: CimZzz
 * @Date: 2022-08-17 15:59:29
 * 
 * 关联共享内存
 * 
 * @return 关联成功返回 true
 * 
 * @note 只有关联成功才可以调用 [getSharedMemory] 获取共享内存地址
 */
bool SharedMemory::attach() {
	if(!this->isInited) {
		return false;
	}
	if(this->isAttached) {
		return true;
	}

	#ifdef VL_POSIX
		auto shmIdPtr = std::static_pointer_cast<int, void>(this->shmId);
		this->sharedMemory = shmat(*shmIdPtr, 0, 0);
		if(this->sharedMemory == (void *)-1) {
			return false;
		}
	#endif //VL_POSIX
	
	this->isAttached = true;
	return true;
}

/**
 * @Author: CimZzz
 * @Date: 2022-08-17 16:01:35
 * 
 * 获取共享内存地址
 * 
 * @return 共享内存地址
 */
void* SharedMemory::getSharedMemory() {
	if(!this->isInited || !this->isAttached) {
		return nullptr;
	}
	return this->sharedMemory;
}

/**
 * @Author: CimZzz
 * @Date: 2022-08-17 15:59:50
 * 
 * 分离共享内存
 * 
 * @return 分离成功返回 true
 */
bool SharedMemory::detach() {
	if(!this->isInited) {
		return false;
	}
	if(!this->isAttached) {
		return true;
	}

	#ifdef VL_POSIX
		if(shmdt(this->sharedMemory) == -1) {
			return false;
		}
		this->sharedMemory = nullptr;
	#endif //VL_POSIX
	
	this->isAttached = false;
	return true;
}

/**
 * @Author: CimZzz
 * @Date: 2022-08-17 16:06:42
 * 
 * 释放共享内存
 * 
 * @return 释放成功返回 true
 */
bool SharedMemory::release() {
	if(!this->isInited) {
		return true;
	}

	if(!detach()) {
		return false;
	}

	if(!this->notCreate) {
		auto shmIdPtr = std::static_pointer_cast<int, void>(this->shmId);
		if(!shmctl(*shmIdPtr, IPC_RMID, 0)) {
			return false;
		}
	}

	this->isInited = false;
	return true;
}

#ifdef VL_POSIX
	/**
	 * @Author: CimZzz
	 * @Date: 2022-08-17 11:48:55
	 * 
	 * 生成信号量 Key 值
	 * 
	 * @param path 项目路径
	 * @param id 项目编号
	 * 
	 * @return 信号量 Key 值
	 */
	std::shared_ptr<void> SharedMemory::generateKey(const char * path, int id) {
		std::shared_ptr<void> keyPtr;

		#ifdef VL_POSIX
			key_t key = ftok(path, id);
			if(key == -1) {
				return keyPtr;
			}

			keyPtr = std::shared_ptr<key_t>(new key_t(key));
		#endif //VL_POSIX

		return keyPtr;
	}
#endif //VL_POSIX